/*
base64code
*/

use std::collections::HashMap;
use std::string::String;
//-------------
use std::sync::mpsc;
use std::thread;
//use std::sync::Mutex;
use std::sync::{Arc, Mutex};
use std::time::Duration;

// 模块形式就要注释这句，如果是bin执行模式 编译就放开这句
// fn main() {
//     println!("Hello, world!");
//     // base64测试
//     base64_test();
// }

// base64测试方法
pub fn base64_test() {
    let source_txt = String::from("愤怒是魔鬼");
    println!("原文：{:?}", source_txt);

    let b64 = base64encode(&source_txt);
    println!("原文转换base64 utf-8编码： {:?}", b64);

    let sb64 = base64decode(&b64);
    println!("base64编码再转换原文 utf-8编码： {:?}", sb64);
}

/// rust 1.27.2编译通过，但是有警告好像

/// base64 编码 算法很烂，还有巨大优化空间
/// 输入一个 字符串 地址 ，这里是&借用，不获取所有权。 返回一个字符串，将所有权返出函数体外
pub fn base64encode(code: &String) -> String {
    let mut result = String::from(""); // 用于存储 结果变量，所以是 mut可变的
    let bytes = code.as_bytes(); // utf-8转换的byte数组，数据基准
    let len = bytes.len(); // 数组长度
    let mut byte_array: [u8; 3] = [0; 3]; // u8;3单个数组，转换过程中用于存储
    let mut byte_vec: Vec<[u8; 3]> = Vec::new(); // 存放u8;3的队列
                                                 // 这一段整体含义是 将byte数组每3个一组拆分，然后放入 Vec<[u8;3]>
    for (i, &item) in bytes.iter().enumerate() {
        // 循环byte数组
        let y = i % 3; // 获得余数 数组角标
        byte_array[y] = item; // byte拷贝值存入 u8;3 数组//不用clone()也没问题
        if y == 2 || i == (len - 1) {
            // 存到一组结尾，和总结尾时
            // println!(" push {:?}", &byte_array);
            // 这里是将 byte_array 拷贝进入 byte_vec。 不是引用进去从而不必考虑所有权问题。
            byte_vec.push(byte_array); // 整体拷贝u8;3数组到 转换队列中，这里没用clone()，居然也行！
            byte_array = [0; 3]; // 重置u8;3数组
        }
    }
    //println!(" byte_vec == {:?}", byte_vec); // 打印一下，可以不打印
    let b_len = byte_vec.len(); // u8;3数组队列长度。决定了转换循环次数
                                // 下面这一段就是 转换 主体 过程 ，具体的字节位移在 后面的函数里面
    for (i, &item) in byte_vec.iter().enumerate() {
        // 循环u8;3 队列 vector
        let a4 = trans_a4(&item); // 转换 u8;4 数组，将 u8;3 转换成 u8;4
                                  // 转换成 u8;4 后 先处理前两位，将对应的字符串提取出来
        result.push(b64_to_char(a4[0])); // 这里后面都是根据对照表提取字符然后存入转换结果
        result.push(b64_to_char(a4[1])); // b64_to_char 内部将字符拷贝值 传出函数返回给 result。  result有字符所有权
        if b_len == i + 1 {
            // 结尾处理 最后一位 (最后组，可能有最多两个位置是0)
            if a4[2] == 0u8 {
                // 值为0 用等号填充，非零就正常填充
                result.push('='); // 结尾处要独立处理 = 号的问题
            } else {
                result.push(b64_to_char(a4[2]));
            }
            if a4[3] == 0u8 {
                // 也是 值为0 用等号填充，非零就正常填充
                result.push('=');
            } else {
                result.push(b64_to_char(a4[3]));
            }
        } else {
            // 非结尾处理
            result.push(b64_to_char(a4[2]));
            result.push(b64_to_char(a4[3]));
        }
    }
    result
}

/// base64 解码 算法很烂，还有巨大优化空间
/// 解码，将base64 转换 为原有的utf-8字符串
pub fn base64decode(code: &String) -> String {
    let mut u8_vec: Vec<u8> = Vec::new(); // 结果队列，byte队列.用于存储字符串的utf8字节组，到字符串还要转换一下
    let mut num_array: [u8; 4] = [0; 4]; // 单个 u8;4数组
    let mut num_vec: Vec<[u8; 4]> = Vec::new(); // u8;4数组队列
    let chars = code.chars(); // base64编码字符队列
    let len = code.len(); // base64编码长度
                          // 这一段 含义 将 base64字符串 字符转换为 u8;4 数组，字符转换角标
    for (i, item) in chars.enumerate() {
        // 循环此编码字符队列

        let y = i % 4; // 用余数分组，每4个为一组
        if item == '=' {
            // 单独处理=号结尾
            num_array[y] = 0u8;
        } else {
            let n = b64_to_num(item); // 将字符对应的编号找到！注意这里传入=在对照表是找不到的，所以在前面处理了=符号
            num_array[y] = n; // 拷贝值存入数组，是不是要拷贝值？不确定。变量归属和声明周期还不熟（不clone也行呢）
        }
        if y == 3 || i == (len - 1) {
            // 分组结尾 和 整个队列结尾单独处理
            // 这里是克隆进去的，所有权一并带入了
            num_vec.push(num_array); // 将u8;4数组拷贝到 队列中// 不拷贝（clone）也行
        }
    }

    //println!(" num_vec == {:?}", num_vec); // 打印中间结果，可以不打印
    let n_len = num_vec.len(); // 计算u8;4数组队列长度
                               // 下面这一段 将 u8;4 缩成 u8;3
    for (i, &item) in num_vec.iter().enumerate() {
        // 开始循环u8;4数组队列
        let a3 = trans_a3(&item); //反向转换 将u8;4数组转换成u8;3数组
        u8_vec.push(a3[0]); //将u8;3数组存储到中间byte队列中
        if i == n_len - 1 {
            // 单独处理结尾的情况
            if a3[1] != 0u8 {
                // 不等于0 继续push
                u8_vec.push(a3[1]);
            }
            if a3[2] != 0u8 {
                u8_vec.push(a3[2]);
            }
        } else {
            u8_vec.push(a3[1]);
            u8_vec.push(a3[2]);
        }
    }
    let result = String::from_utf8(u8_vec).unwrap(); // 这里将u8;3队列转换成utf-8字符串
    result
}

/// 这是个样本方法，摘抄来参考的 base64没用到此方法
pub fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}

/// u8;3 数组转换 u8;4数组
pub fn trans_a4(a3: &[u8; 3]) -> [u8; 4] {
    // 就是3位8byte，转换成4位6byte组
    let mut a4: [u8; 4] = [0; 4];
    a4[0] = a3[0] >> 2; //0右移2位
    a4[1] = (a3[0] << 6) >> 2 | a3[1] >> 4; //0左移6位再右移2位和1右移4位组合
    a4[2] = (a3[1] << 4) >> 2 | a3[2] >> 6; //1左移4位再右移2位和2右移6位组合
    a4[3] = (a3[2] << 2) >> 2; //2左移2位再右移2位//其实可以直接将左两位异或0b00
    a4
}

/// u8;4 数组转换 u8;3数组
pub fn trans_a3(a4: &[u8; 4]) -> [u8; 3] {
    // 就是4位6byte，转换成3位8byte组
    let mut a3: [u8; 3] = [0; 3];
    a3[0] = a4[0] << 2 | a4[1] >> 4; //0左移2位组合1右移4位
    a3[1] = a4[1] << 4 | a4[2] >> 2; //1左移4位组合2右移2位
    a3[2] = a4[2] << 6 | a4[3]; //2左移6位组合3全部
    a3
}

/// 用key 获取char
pub fn b64_to_char(key: u8) -> char {
    // 下面这段程序用B64_ARY当作查询基准 也可以运行
    // let mut c:char = ' ';
    // for pat in B64_ARY.iter() {
    //     if pat.0 == key {
    //         c = pat.1;
    //         break;
    //     }
    // }
    // c
    // 下面是用 B64_STR 做基准查询 str.get 方法没用上，以后研究
    let mut c: char = '-';
    let mut i: u64 = 0;
    for pat in B64_STR.chars() {
        if i == key as u64 {
            c = pat;
            break;
        }
        i += 1;
    }
    c
}

/// 用char 获取 key编号
pub fn b64_to_num(key: char) -> u8 {
    // 下面这段程序用B64_ARY当作查询基准 也可以运行
    // let mut n:u8 = 0;
    // for pat in B64_ARY.iter() {
    //     if pat.1 == key {
    //         n = pat.0;
    //         break;
    //     }
    // }
    // n
    // 下面是用 B64_STR 做基准查询
    if key == '=' {
        //如果查询= 直接返回0
        return 0 as u8;
    }
    let n = B64_STR.find(key).unwrap();
    n as u8
}

// 元祖数组类型 b64对照表
const B64_ARY: [(u8, char); 64] = [
    (0, 'A'),
    (1, 'B'),
    (2, 'C'),
    (3, 'D'),
    (4, 'E'),
    (5, 'F'),
    (6, 'G'),
    (7, 'H'),
    (8, 'I'),
    (9, 'J'),
    (10, 'K'),
    (11, 'L'),
    (12, 'M'),
    (13, 'N'),
    (14, 'O'),
    (15, 'P'),
    (16, 'Q'),
    (17, 'R'),
    (18, 'S'),
    (19, 'T'),
    (20, 'U'),
    (21, 'V'),
    (22, 'W'),
    (23, 'X'),
    (24, 'Y'),
    (25, 'Z'),
    (26, 'a'),
    (27, 'b'),
    (28, 'c'),
    (29, 'd'),
    (30, 'e'),
    (31, 'f'),
    (32, 'g'),
    (33, 'h'),
    (34, 'i'),
    (35, 'j'),
    (36, 'k'),
    (37, 'l'),
    (38, 'm'),
    (39, 'n'),
    (40, 'o'),
    (41, 'p'),
    (42, 'q'),
    (43, 'r'),
    (44, 's'),
    (45, 't'),
    (46, 'u'),
    (47, 'v'),
    (48, 'w'),
    (49, 'x'),
    (50, 'y'),
    (51, 'z'),
    (52, '0'),
    (53, '1'),
    (54, '2'),
    (55, '3'),
    (56, '4'),
    (57, '5'),
    (58, '6'),
    (59, '7'),
    (60, '8'),
    (61, '9'),
    (62, '+'),
    (63, '/'),
];

// const B64_MAP:HashMap<u8, char> = [(0, 'A')].iter().cloned().collect();
// str类型 b64对照表
const B64_STR: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//////////////////////////////=====================================================================

/// base64测试方法
pub fn base64_thread_test() {
    let big_str: String = String::from("愤怒是魔鬼");
    println!("原文：{:?}", big_str);

    let amt_str = Arc::new(Mutex::new(String::from(big_str)));
    let enbase64_res = base64encode_thread(amt_str);
    println!(" EN BASE64 RESULT : {:?}", enbase64_res);
    //let str2: String = String::from(big_str.clone());
    //let b64_res = myb64::base64encode(&str2);
    //println!(" base64 result: {:?}", b64_res);
    let code_str = Arc::new(Mutex::new(String::from(enbase64_res)));
    let debase64_res = base64decode_thread(code_str);
    println!(" DE BASE64 RESULT : {:?}", debase64_res);
}

/// base64编码 线程+通道版本
///
/// # Examples
///
/// ```
/// let big_str: String = String::from("愤怒是魔鬼...");
/// let amt_str = Arc::new(Mutex::new(String::from(big_str)));
/// let enbase64_res = base64encode_2(amt_str);
/// println!(" EN BASE64 RESULT : {:?}", enbase64_res);
/// ```
pub fn base64encode_thread(soustr: Arc<Mutex<String>>) -> String {
    let (tx, rx) = mpsc::channel(); // 创建 数据 通道，用于传递
                                    //let sc = soustr.clone(); // 可以不用拷贝
    thread::spawn(move || {
        // 线程，将输入参数移动到线程内部
        let mut idx: usize = 0; // 循环位移标记
        let mut byte_array: [u8; 3] = [0; 3]; // u8;3数组 三位数组
        let bb = soustr.lock().unwrap(); // 锁定 并使用
        let mut peek = bb.bytes().peekable(); // 获取一个可窥视的对象，必须是可修改的，用于观察结果
        for val in bb.bytes() {
            // 迭代
            let idx_i = idx % 3; // 计算索引除以3 余数
                                 //println!(" {:?} : {:?}", idx_i, val); // 打印日志
            byte_array[idx_i] = val; // 装数据，每3个装一组，不足的用0代替装满
            if idx_i == 2 || peek.peek() == None {
                // 检查3间断和结尾，发送数据
                tx.send(byte_array).unwrap(); // 向通道发送数据（应该是拷贝发送的）
                byte_array = [0; 3]; // 重置 数据，准备下一次装
            }
            //thread::sleep(Duration::from_secs(1));
            idx += 1; // 索引号加1
        }
    });

    let mut result: String = String::from(""); // 声明可修改的结果
    for received in rx {
        // 迭代接收通道
        //println!("thread_borrow Got: {:?}", received);
        let a4 = trans_a4(&received); // 接收值转换 u8;4数组
                                      //println!(" a4 = {:?}", a4);
        result.push(b64_to_char(a4[0])); // 这里后面都是根据对照表提取字符然后存入转换结果
        result.push(b64_to_char(a4[1])); // b64_to_char 内部将字符拷贝值 传出函数返回给 result。  result有字符所有权
                                         // 结尾处理 最后一位 (最后组，可能有最多两个位置是0)
        if a4[2] == 0u8 {
            // 值为0 用等号填充，非零就正常填充
            result.push('='); // 结尾处要独立处理 = 号的问题
        } else {
            result.push(b64_to_char(a4[2]));
        }
        if a4[3] == 0u8 {
            // 也是 值为0 用等号填充，非零就正常填充
            result.push('=');
        } else {
            result.push(b64_to_char(a4[3]));
        }
        // if a4[2] == 0 || a4[3] == 0 { // 如果出现后两位 或者最后一位 是0，就表明是最后一组了。或者可以用迭代peek来处理

        // } else {
        //     // 非结尾处理
        //     result.push(b64_to_char(a4[2]));
        //     result.push(b64_to_char(a4[3]));
        // }
    }
    result
}

/// base64解码 线程+通道版本
///
/// # Examples
///
/// ```
/// let big_str: String = String::from("愤怒是魔鬼...");
/// let code_str = Arc::new(Mutex::new(String::from(enbase64_res)));
/// let debase64_res = base64decode_thread(code_str);
/// println!(" DE BASE64 RESULT : {:?}", debase64_res);
/// ```
pub fn base64decode_thread(soustr: Arc<Mutex<String>>) -> String {
    let (tx, rx) = mpsc::channel(); // 创建通道
                                    // let sc = soustr.clone();
    thread::spawn(move || {
        // 启动线程，闭包 捕获 数据
        let mut idx: usize = 0; // 循环索引号
        let mut num_array: [u8; 4] = [0; 4]; // u8;4数组
        let lock_char_array = soustr.lock().unwrap(); // 锁定
        let mut peek = lock_char_array.chars().peekable(); // 可窥视，用于检查结尾
        for c in lock_char_array.chars() {
            // 迭代base64字符
            let idx_i = idx % 4; // 每4分组
                                 //println!(" {:?} : {:?}", idx_i, val);
            if c == '=' {
                // =就是 0u8
                num_array[idx_i] = 0u8;
            } else {
                num_array[idx_i] = b64_to_num(c); // 不是=就转成标号送入数组
            }
            if idx_i == 3 || peek.peek() == None {
                // 检查结尾
                tx.send(num_array).unwrap(); // 发送到通道
                num_array = [0; 4]; // 重置u8;4数组
            }
            //thread::sleep(Duration::from_secs(1));
            idx += 1;
        }
    });
    let mut u8_vec: Vec<u8> = Vec::new();
    for received in rx {
        //println!("thread_borrow Got: {:?}", received);
        let a3 = trans_a3(&received); //反向转换 将u8;4数组转换成u8;3数组
        u8_vec.push(a3[0]); //将u8;3数组存储到中间byte队列中
        if a3[1] != 0u8 {
            // 不等于0 继续push
            u8_vec.push(a3[1]);
        }
        if a3[2] != 0u8 {
            u8_vec.push(a3[2]);
        }
    }
    let result = String::from_utf8(u8_vec).unwrap(); // 这里将u8;3队列转换成utf-8字符串
    result
}
